﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.ServiceProcess;

namespace Sunny.Lib
{
    /// <summary>
    /// 提供windows服务的注册、反注册功能
    /// </summary>
    public class Register
    {
        // declare APIs for service
        [DllImport("advapi32.dll")]
        public static extern System.IntPtr OpenSCManager(
          System.String lpMachineName,
          System.String lpDatabaseName,
          System.UInt32 dwDesiredAccess
         );
        [DllImport("advapi32.dll", EntryPoint = "CreateServiceA")]
        public static extern System.IntPtr CreateService(
          System.IntPtr hSCManager,
          System.String lpServiceName,
          System.String lpDisplayName,
          System.UInt32 dwDesiredAccess,
          System.UInt32 dwServiceType,
          System.UInt32 dwStartType,
          System.UInt32 dwErrorControl,
          System.String lpBinaryPathName,
          System.String lpLoadOrderGroup,
          System.IntPtr lpdwTagId,
          System.String lpDependencies,
          System.String lpServiceStartName,
          System.String lpPassword
         );
        [DllImport("advapi32.dll")]
        public static extern System.IntPtr OpenService(
          System.IntPtr hSCManager,
          System.String lpServiceName,
          System.UInt32 dwDesiredAccess
         );
        [DllImport("advapi32.dll")]
        public static extern System.Boolean DeleteService(
          System.IntPtr hService
         );
        [DllImport("advapi32.dll")]
        public static extern System.Boolean CloseServiceHandle(
          System.IntPtr hSCObject
         );
        [DllImport("advapi32.dll")]
        public static extern System.Boolean ChangeServiceConfig2(
          System.IntPtr hService,
          System.UInt32 dwInfoLevel,
          ref System.String lpInfo
         );

        public const System.UInt32 STANDARD_RIGHTS_REQUIRED = 0xF0000;
        // Service Control Manager object specific access types
        public const System.UInt32 SC_MANAGER_CONNECT = 0x0001;
        public const System.UInt32 SC_MANAGER_CREATE_SERVICE = 0x0002;
        public const System.UInt32 SC_MANAGER_ENUMERATE_SERVICE = 0x0004;
        public const System.UInt32 SC_MANAGER_LOCK = 0x0008;
        public const System.UInt32 SC_MANAGER_QUERY_LOCK_STATUS = 0x0010;
        public const System.UInt32 SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020;
        public const System.UInt32 SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
          SC_MANAGER_CONNECT |
          SC_MANAGER_CREATE_SERVICE |
          SC_MANAGER_ENUMERATE_SERVICE |
          SC_MANAGER_LOCK |
          SC_MANAGER_QUERY_LOCK_STATUS |
          SC_MANAGER_MODIFY_BOOT_CONFIG;
        // Service object specific access type
        public const System.UInt32 SERVICE_QUERY_CONFIG = 0x0001;
        public const System.UInt32 SERVICE_CHANGE_CONFIG = 0x0002;
        public const System.UInt32 SERVICE_QUERY_STATUS = 0x0004;
        public const System.UInt32 SERVICE_ENUMERATE_DEPENDENTS = 0x0008;
        public const System.UInt32 SERVICE_START = 0x0010;
        public const System.UInt32 SERVICE_STOP = 0x0020;
        public const System.UInt32 SERVICE_PAUSE_CONTINUE = 0x0040;
        public const System.UInt32 SERVICE_INTERROGATE = 0x0080;
        public const System.UInt32 SERVICE_USER_DEFINED_CONTROL = 0x0100;
        public const System.UInt32 SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
          SERVICE_QUERY_CONFIG |
          SERVICE_CHANGE_CONFIG |
          SERVICE_QUERY_STATUS |
          SERVICE_ENUMERATE_DEPENDENTS |
          SERVICE_START |
          SERVICE_STOP |
          SERVICE_PAUSE_CONTINUE |
          SERVICE_INTERROGATE |
          SERVICE_USER_DEFINED_CONTROL;
        // service type
        public const System.UInt32 SERVICE_KERNEL_DRIVER = 0x00000001;
        public const System.UInt32 SERVICE_FILE_SYSTEM_DRIVER = 0x00000002;
        public const System.UInt32 SERVICE_ADAPTER = 0x00000004;
        public const System.UInt32 SERVICE_RECOGNIZER_DRIVER = 0x00000008;
        public const System.UInt32 SERVICE_DRIVER = SERVICE_KERNEL_DRIVER |
          SERVICE_FILE_SYSTEM_DRIVER |
          SERVICE_RECOGNIZER_DRIVER;
        public const System.UInt32 SERVICE_WIN32_OWN_PROCESS = 0x00000010;
        public const System.UInt32 SERVICE_WIN32_SHARE_PROCESS = 0x00000020;
        public const System.UInt32 SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS |
          SERVICE_WIN32_SHARE_PROCESS;
        public const System.UInt32 SERVICE_INTERACTIVE_PROCESS = 0x00000100;
        public const System.UInt32 SERVICE_TYPE_ALL = SERVICE_WIN32 |
          SERVICE_ADAPTER |
          SERVICE_DRIVER |
          SERVICE_INTERACTIVE_PROCESS;
        // Start Type
        public const System.UInt32 SERVICE_BOOT_START = 0x00000000;
        public const System.UInt32 SERVICE_SYSTEM_START = 0x00000001;
        public const System.UInt32 SERVICE_AUTO_START = 0x00000002;//自动
        public const System.UInt32 SERVICE_DEMAND_START = 0x00000003;//手动
        public const System.UInt32 SERVICE_DISABLED = 0x00000004;//禁用
        // Error control type
        public const System.UInt32 SERVICE_ERROR_IGNORE = 0x00000000;
        public const System.UInt32 SERVICE_ERROR_NORMAL = 0x00000001;
        public const System.UInt32 SERVICE_ERROR_SEVERE = 0x00000002;
        public const System.UInt32 SERVICE_ERROR_CRITICAL = 0x00000003;
        // Info levels for ChangeServiceConfig2 and QueryServiceConfig2
        public const System.UInt32 SERVICE_CONFIG_DESCRIPTION = 1;
        public const System.UInt32 SERVICE_CONFIG_FAILURE_ACTIONS = 2;

        /// <summary>
        /// 注册服务
        /// </summary>
        /// <param name="path"></param>
        /// <param name="serverName"></param>
        /// <param name="disName"></param>
        /// <param name="discription"></param>
        /// <returns></returns>
        public static System.Boolean RegistService(string path, string serverName, string disName, string discription, uint runTye)
        {
            System.Boolean fRet = false;
            System.IntPtr hServiceManager = IntPtr.Zero, hService = IntPtr.Zero;
            System.String sServicePath = null, sDesc = null;

            sServicePath = path;
            hServiceManager = OpenSCManager(Environment.MachineName, null, SC_MANAGER_ALL_ACCESS);
            if (hServiceManager != IntPtr.Zero)
            {
                hService = CreateService(hServiceManager, serverName, disName, SERVICE_ALL_ACCESS,
                 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, runTye, SERVICE_ERROR_NORMAL,
                 sServicePath, null, IntPtr.Zero, null, null, null);
                if (hService != IntPtr.Zero)
                {
                    sDesc = discription;
                    fRet = ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, ref sDesc);
                    CloseServiceHandle(hService);
                    hService = IntPtr.Zero;
                }
                CloseServiceHandle(hServiceManager);
                hServiceManager = IntPtr.Zero;
            }
            return fRet;
        }

        /// <summary>
        /// 反注册服务
        /// </summary>
        /// <param name="serverName"></param>
        /// <returns></returns>
        public static System.Boolean UnRegistService(string serverName)
        {
            System.Boolean fRet = false;
            System.IntPtr hServiceManager = IntPtr.Zero, hService = IntPtr.Zero;

            hServiceManager = OpenSCManager(Environment.MachineName, null, SC_MANAGER_ALL_ACCESS);
            if (hServiceManager != IntPtr.Zero)
            {
                hService = OpenService(hServiceManager, serverName, SERVICE_ALL_ACCESS);
                if (hService != IntPtr.Zero)
                {
                    fRet = DeleteService(hService);
                    CloseServiceHandle(hService);
                    hService = IntPtr.Zero;
                }
                CloseServiceHandle(hServiceManager);
                hServiceManager = IntPtr.Zero;
            }
            return fRet;
        }

        /// <summary>
        /// 设置服务的启动类型
        /// </summary>
        /// <param name="serverName"></param>
        /// <param name="runType"></param>
        /// <returns></returns>
        public static System.Boolean ChangeServiceRunType(string serverName, int runType)
        {
            System.Security.Permissions.RegistryPermission permission =
              new System.Security.Permissions.RegistryPermission(
              System.Security.Permissions.RegistryPermissionAccess.AllAccess,
              @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\" + serverName);

            try
            {
                Microsoft.Win32.RegistryKey runKey =
                Microsoft.Win32.Registry.LocalMachine.
                OpenSubKey(@"SYSTEM\CurrentControlSet\Services\" + serverName, true);
                if (runKey != null)
                {
                    runKey.SetValue("Start", runType);
                }
                return true;
            }
            finally
            {
            }
        }

        /// <summary>
        /// 获取服务的启动类型
        /// </summary>
        /// <param name="serverName"></param>
        /// <param name="runType"></param>
        public static string GetServiceRunType(string serverName)
        {
            string runType = "";
            System.Security.Permissions.RegistryPermission permission =
              new System.Security.Permissions.RegistryPermission(
              System.Security.Permissions.RegistryPermissionAccess.AllAccess,
              @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\" + serverName);

            try
            {
                Microsoft.Win32.RegistryKey runKey =
                Microsoft.Win32.Registry.LocalMachine.
                OpenSubKey(@"SYSTEM\CurrentControlSet\Services\" + serverName, true);
                if (runKey != null)
                {
                    runType = runKey.GetValue("Start").ToString ();
                }
            }
            finally
            {
                
            }
            return runType;
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        /// <param name="serverName"></param>
        /// <returns></returns>
        public static bool StopService(string serverName)
        {
            ServiceController sc = new ServiceController(serverName);
            try
            {
                if (!((sc.Status.Equals(ServiceControllerStatus.Stopped)) ||
         (sc.Status.Equals(ServiceControllerStatus.StopPending))))
                {
                    sc.Stop();
                    sc.Refresh();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 启动/继续服务
        /// </summary>
        /// <param name="serverName"></param>
        /// <returns></returns>
        public static bool StartService(string serverName)
        {
            ServiceController sc = new ServiceController(serverName);
            try
            {
                if ((sc.Status.Equals(ServiceControllerStatus.Stopped)) ||
         (sc.Status.Equals(ServiceControllerStatus.StopPending)))
                {
                    sc.Start();
                    sc.Refresh();
                }

                if ((sc.Status.Equals(ServiceControllerStatus.Paused)) ||
         (sc.Status.Equals(ServiceControllerStatus.PausePending)))
                {
                    sc.Continue();
                    sc.Refresh();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 暂停服务
        /// </summary>
        /// <returns></returns>
        public static bool PauseService(string serverName)
        {
            ServiceController sc = new ServiceController(serverName);
            try
            {
                if (!((sc.Status.Equals(ServiceControllerStatus.Paused)) ||
         (sc.Status.Equals(ServiceControllerStatus.PausePending))))
                {
                    sc.Pause();
                    sc.Refresh();
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}
